"""
通用接口

"""
import json
import os
import time
import uuid
from io import BytesIO

import requests
from PIL import Image
from dotenv import load_dotenv
from flask import Blueprint, g, request

from components.nacos.service import proxy_service
from controller.common import handel_cache
from models.user import User
from utils.views import resp_with_data, valid, create_verify_code, rewrite_request
from utils.wx import get_access_token
from components.base_exception import ParamsError, NotFoundError, CallBackError, ConfirmPwdError
from components.base_log import log_method_call
from components.memcache.connector import cache
from components.sms import SMS

load_dotenv('env.ini', encoding='utf-8')
common_bp = Blueprint('common', __name__)


@common_bp.route('/keeping_connect', methods=['GET'])
def keeping_connect():
    return resp_with_data('OK')


@common_bp.route('/get_sms', methods=['POST'])
@log_method_call(action='sms')
def get_sms():
    """
    获取短信验证码
    """
    phone = g.json.get('phone')
    valid_res = valid(
        (phone, '手机号必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    if not cache.get('phone'):
        code = create_verify_code()
        res = SMS.send(phone, code)
        if res.get('status') != 0:
            return resp_with_data(10001)
        cache.set(str(phone), code, time=int(os.getenv('SMS_CODE_EXPIRE_TIME')))
    else:
        return resp_with_data(10002)
    return resp_with_data(10000)


@common_bp.route('/sms_login', methods=['POST'])
@log_method_call(action='sms_login')
def sms_login():
    """
    短信登录
    """
    phone = g.json.get('phone')
    code = g.json.get('code')
    valid_res = valid(
        (phone, '手机号必填'),
        (code, '验证码必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    sms_code = cache.get(str(phone))
    if not sms_code:
        return resp_with_data(10003, msg='验证码过期')
    if code != sms_code:
        return resp_with_data(10003, msg='验证码错误')

    user = User.get_or_none(User.phone == phone, User.is_del == False)
    if not user:
        raise NotFoundError()
    data = handel_cache(user.id, 'for_sms')
    cache.delete(str(phone))
    return resp_with_data(10000, data=data)


@common_bp.route('/password_login', methods=['POST'])
@log_method_call(action='login')
def password_login():
    phone = g.json.get('phone')
    password = g.json.get('password')
    valid_res = valid(
        (phone, '手机号必填'),
        (password, '密码必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    user = User.get_or_none(User.phone == g.json.get('phone'))
    if not user:
        raise NotFoundError()
    if not user.validate_password(g.json.get('password')):
        return resp_with_data(10004, '密码错误')
    data = handel_cache(user.id, 'for_pwd')
    return resp_with_data(10000, data=data)


@common_bp.route('/register', methods=['POST'])
@log_method_call(action='')
def register():
    name = g.json.get('phone')
    phone = g.json.get('phone')
    password = g.json.get('password')
    email = g.json.get('password')
    org = g.json.get('org_id')

    valid_res = valid(
        (phone, '手机号'),
        (password, '密码'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    User.create(
        name=name,
        phone=phone,
        password=password,
        email=email,
        org_id=org
    )


@common_bp.route('/get_wx_info', methods=['POST'])
@log_method_call(action='')
def get_wx_info():
    code = g.json.get('code')
    valid_res = valid(
        (code, 'code必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)

    app_id = os.getenv('WX_APP_ID')
    app_secret = os.getenv('WX_APP_SECRET')
    info = requests.get("https://api.weixin.qq.com/sns/jscode2session?appid="
                        + app_id + "&secret=" + app_secret + "&js_code=" + code + "&grant_type=authorization_code")

    return resp_with_data(10000, json.loads(info.content.decode('utf-8')))


@common_bp.route('/wx_login', methods=['POST'])
@log_method_call(action='')
def wx_login():
    wx_uid = g.json.get('wx_uid')
    valid_res = valid(
        (wx_uid, '微信uuid必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    user = User.get_or_none(User.wx_uid == wx_uid)
    if not user:
        raise NotFoundError()
    data = handel_cache(user.id, type='for_wx_phone')
    return resp_with_data(10000, data=data)


@common_bp.route('/wx_login_with_phone', methods=['POST'])
@log_method_call(action='')
def wx_login_with_phone():
    wx_uid = g.json.get('wx_uid')
    phone = g.json.get('phone')
    valid_res = valid(
        (wx_uid, '微信uuid必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    # 解绑之前的wx_uid
    wx_exist = User.get_or_none(User.wx_uid == wx_uid)
    if wx_exist:
        if wx_exist.phone != phone:
            wx_exist.wx_uid = ''
            wx_exist.save()
    user = User.get_or_none(User.phone == phone, User.is_del == False)
    if not user:
        raise NotFoundError()
    if user.wx_uid != wx_uid:
        user.wx_uid = wx_uid
        user.save()
    data = handel_cache(user.id, type='for_wx_phone')
    return resp_with_data(10000, data=data)


@common_bp.route('/update_password', methods=['POST'])
@log_method_call(action='Update')
def update_user_password():
    """
    修改密码
    """
    new_password = g.json.get('new_password')
    confirm_password = g.json.get('confirm_password')
    old_password = g.json.get('old_password')
    valid_res = valid(
        (new_password, '新密码必填'),
        (old_password, '旧密码必填'),
        (confirm_password, '确认密码必填'),
    )
    if valid_res:
        raise ParamsError(data=valid_res)
    user = User.get_or_none(User.id == g.user_id)
    if not user:
        raise NotFoundError()
    if new_password != confirm_password:
        raise ConfirmPwdError()

    if user.validate_password(g.json.get('old_password')):
        user.password = g.json.get('new_password')
        user.save()
    else:
        return resp_with_data(10015, data=False)
    return resp_with_data(10000, data=True)


@common_bp.route('/long_server', methods=['GET'])
@log_method_call(action='')
def long_server():
    """
    监控着字典里的key对应的status,如果为success,返回数据
    """
    request_time = time.time()
    while True:
        # 获取传递过来的key
        uni_key = request.args.get('uni_key')
        info_dict = {}
        time.sleep(1)
        global_dict = json.loads(cache.get('qr_code'.encode('utf-8')))
        if global_dict:
            for info in list(global_dict.keys()):
                if time.time() - global_dict[info]['exp_time'] > 300:
                    del global_dict[info]
                    cache.set("qr_code", json.dumps(global_dict))
                if time.time() - request_time > 55:
                    return resp_with_data(10013)
                try:
                    info_dict[global_dict[info]['uni_key']] = {}
                    info_dict[global_dict[info]['uni_key']]['status'] = \
                        global_dict[info]['status'] if 'status' in global_dict[info] else None
                    info_dict[global_dict[info]['uni_key']]['data'] = global_dict[info]
                except Exception as e:
                    print(e)
            if info_dict:
                if uni_key in info_dict.keys() and info_dict[uni_key]['status'] == 'success':
                    user_id = info_dict[uni_key]['info']['user_id']
                    data = handel_cache(user_id, 'for_code')
                    return resp_with_data(10000, data=data)


@common_bp.route('/qr_code', methods=['POST'])
@log_method_call(action='')
def generate_qr_code():
    uni_key = g.json.get('uni_key')
    key = ''.join(str(uuid.uuid4()).split('-'))[:16]
    info = {'status': 'fail',
            'exp_time': time.time(),
            'uni_key': uni_key}
    if cache.get('qr_code'.encode('utf-8')):
        # 应该要增加, 而不是直接set
        global_dict = json.loads(cache.get('qr_code'.encode('utf-8')))
        global_dict.update({key: info})
        cache.set('qr_code', json.dumps(global_dict))
    else:
        cache.set("qr_code", json.dumps({key: info}))
    url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s" % get_access_token()
    body = {
        "scene": "key=%s" % key,
        "page": "pages/login/index",
        "env_version": os.getenv('WX_VERSION'),  # 指定小程序版本  正式版 release  体验版 trial 开发版develop
        "is_hyaline": True,
    }
    res = requests.post(url, data=json.dumps(body))

    image = Image.open(BytesIO(res.content))
    image = image.convert('RGB')
    file_name = 'Code' + time.strftime('%Y%m%d%H%M%S') + '.jpg'
    root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    upload_path = os.path.join(root_path, 'static', 'upload')
    real_path = os.path.join(upload_path, file_name)
    image.save(real_path)
    data = {
        "url": "/static/upload/" + file_name
    }
    return resp_with_data(10000, data=data)


@common_bp.route('/callback', methods=['POST'])
@log_method_call(action='')
def handle_callback():
    global_dict = json.loads(cache.get('qr_code'.encode('utf-8')))
    try:
        key = g.json.get('key')
        global_dict[key]['status'] = 'success'
        global_dict[key]['info'] = {'user_id': g.json.get('user_id')}
        cache.set('qr_code', json.dumps(global_dict))
        return resp_with_data(10000)
    except Exception:
        raise CallBackError()


# 测试调用其他服务
@common_bp.route('/auth', methods=['GET'])
def authenticate():
    # 测试调用其他应用
    # 调用参数
    args = {'version': 'v1.0', 'page': 1}
    data = {'name': 'test'}
    headers = {'version': "v2.0"}
    # 重写请求
    rewrite_request('GET', args, data, headers)
    # 调用user服务 user蓝图 users方法
    response = proxy_service('user', 'user/users', request)
    # print(request.args.get('version'))
    # print(response, response.status_code, response.text, response.content)
    if type(response) == dict:
        return response
    return response.content
